﻿@page "/wafer-map"
@using Radzen.Blazor

<RadzenCard class="rz-p-0">
    <RadzenRow JustifyContent="@justifyContent" AlignItems="@alignItems" Gap="@gap" class="rz-border-info-light">
        <RadzenColumn>
            <canvas id="waferCanvas" width="600" height="600" style="border: 1px solid black;"></canvas>
            <canvas id="waferZoomCanvas" width="200" height="200" style="border: 1px solid black;"></canvas>
        </RadzenColumn>
        <RadzenColumn>

            @* <div style="display: flex;">
                <!-- SVG 部分 -->
                <svg width="400" height="400" viewBox="0 0 400 400" style="border: 1px solid black; transform: scale(1.8); transform-origin: 0 0;">
                <!-- 绘制晶圆 -->
                <circle cx="200" cy="200" r="150" fill="none" stroke="black" stroke-width="2" />

                <!-- 绘制X轴和Y轴 -->
                <line x1="50" y1="200" x2="350" y2="200" stroke="black" stroke-width="1" />
                <line x1="200" y1="50" x2="200" y2="350" stroke="black" stroke-width="1" />

                <!-- 绘制 Shots -->
                @foreach (var shot in Shots)
                {
                <rect x="@shot.DisplayX" y="@shot.DisplayY" width="@ShotWidth" height="@ShotHeight" fill="@shot.FillColor" stroke="black"
                @onmouseover="() => ShowShotInfo(shot)"/>
                }

                <!-- 显示当前 Shot 的坐标信息 -->
                <text x="10" y="390" font-family="Verdana" font-size="12" fill="black">
                @($"X: {currentX} mm, Y: {currentY} mm  Shot位置:{currentGridX},{currentGridY}")
                </text>
                </svg>
                </div> *@

            <!-- 输入框和按钮部分 -->
            <RadzenStack Orientation="Radzen.Orientation.Horizontal" AlignItems="AlignItems.Start" Wrap="FlexWrap.Wrap">
                <RadzenStack Orientation="Radzen.Orientation.Vertical" Gap="4px">
                    ZeroShotOffsetX
                    <RadzenNumeric type="text" @bind-Value="ZeroShotOffsetX" placeholder="ZeroShotOffsetX" style="width: 150px; height: 30px;" />
                </RadzenStack>
                <RadzenStack Orientation="Radzen.Orientation.Vertical" Gap="4px">
                    ZeroShotOffsetY
                    <RadzenNumeric type="text" @bind-Value="ZeroShotOffsetY" placeholder="ZeroShotOffsetY" style="width: 150px; height: 30px;" />
                </RadzenStack>
                <RadzenStack Orientation="Radzen.Orientation.Vertical" Gap="4px">
                    RotationDegree
                    <RadzenNumeric type="text" @bind-Value="RotationDegree" placeholder="RotationDegree" style="width: 150px; height: 30px;" />
                </RadzenStack>
                <RadzenStack Orientation="Radzen.Orientation.Vertical" Gap="4px">
                    ShotWidth
                    <RadzenNumeric type="text" @bind-Value="ShotWidth" placeholder="ShotWidth" style="width: 150px; height: 30px;" />
                </RadzenStack>
                <RadzenStack Orientation="Radzen.Orientation.Vertical" Gap="4px">
                    ShotHeight
                    <RadzenNumeric type="text" @bind-Value="ShotHeight" placeholder="ShotHeight" style="width: 150px; height: 30px;" />
                </RadzenStack>
                <RadzenStack Orientation="Radzen.Orientation.Horizontal" Gap="4px">
                    <RadzenCheckBox @bind-Value=@IsShowShotInside Name="IsShowShotInside" style="margin-top:30px;" />
                    <RadzenLabel Text="IsShowShotInside" Component="IsShowShotInside" class="rz-ms-2" style="margin-top:30px;" />
                </RadzenStack>

                <RadzenStack Orientation="Radzen.Orientation.Vertical" Gap="4px">
                    <RadzenRow>
                        Filter Max Radius
                        <RadzenNumeric type="text" @bind-Value="FilterMaxRadius" style="width: 150px; height: 30px;" />
                        Filter Min Radius
                        <RadzenNumeric type="text" @bind-Value="FilterMinRadius" style="width: 150px; height: 30px;" />
                    </RadzenRow>
                    <RadzenRow>
                        <Button Text="Filter" OnClick="FilterRadiusClick" />
                    </RadzenRow>
                </RadzenStack>

                <Button Type="@AntDesign.ButtonType.Primary" @onclick="GenerateWaferMap" style="width: 150px; height: 30px; margin-top:25px;">GenerateWaferMap</Button>

                <Row>
                    <RadzenStack Orientation="Radzen.Orientation.Vertical" Gap="4px">
                        ShotX
                        <RadzenNumeric type="text" @bind-Value="ShotX" placeholder="ShotX" style="width: 150px; height: 30px;" />
                    </RadzenStack>
                    <RadzenStack Orientation="Radzen.Orientation.Vertical" Gap="4px">
                        ShotY
                        <RadzenNumeric type="text" @bind-Value="ShotY" placeholder="ShotY" style="width: 150px; height: 30px; " />
                    </RadzenStack>
                    <RadzenStack Orientation="Radzen.Orientation.Horizontal" Gap="4px;">
                        <Button Type="@AntDesign.ButtonType.Primary" @onclick="MoveToTargetShot" style="width: 150px; height: 30px; margin-top:25px;">Move to Target Shot</Button>
                    </RadzenStack>
                </Row>
            </RadzenStack>
        </RadzenColumn>
    </RadzenRow>

    <RadzenRow JustifyContent="@justifyContent" AlignItems="@alignItems" Gap="@gap" class="rz-border-info-light">
        <RadzenDataGrid EditMode="DataGridEditMode.Single" @ref=grid TItem="ToiModel" AllowPaging="false" PageSize="5" AllowSorting="false"
                        Data="@tois" RowUpdate="@OnUpdateRow"
                        ColumnWidth="200px" AllowColumnResize="true">
            <Columns>
                <RadzenDataGridColumn TItem="ToiModel" Property=@nameof(ToiModel.Name) Title=@nameof(ToiModel.Name) Width="120px" IsInEditMode="@IsEditing">
                    <Template Context="data">
                        <RadzenText Text="@(data.Name)" />
                    </Template>
                    <EditTemplate Context="data">
                        <RadzenTextBox @bind-Value="data.Name" Style="width:120px; display: block" Name=@nameof(ToiModel.Name) />
                    </EditTemplate>
                </RadzenDataGridColumn>

                <RadzenDataGridColumn TItem="ToiModel" Property=@nameof(ToiModel.X) Title=@nameof(ToiModel.X) IsInEditMode="@IsEditing">
                    <Template Context="data">
                        <RadzenText Text="@(data.X.ToString())" />
                    </Template>
                    <EditTemplate Context="data">
                        <RadzenNumeric @bind-Value=data.X Style="width:100%" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "Select freight" }})" />
                    </EditTemplate>
                </RadzenDataGridColumn>

                <RadzenDataGridColumn TItem="ToiModel" Property=@nameof(ToiModel.Y) Title=@nameof(ToiModel.Y) IsInEditMode="@IsEditing">
                    <Template Context="data">
                        <RadzenText Text="@(data.Y.ToString())" />
                    </Template>
                    <EditTemplate Context="data">
                        <RadzenNumeric @bind-Value=data.Y Style="width:100%" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "Select freight" }})" />
                    </EditTemplate>
                </RadzenDataGridColumn>

                <RadzenDataGridColumn Width="80px" TItem="ToiModel" Filterable="false" Sortable="false" TextAlign="Radzen.TextAlign.Center" Frozen="true" FrozenPosition="FrozenColumnPosition.Right">
                    <Template Context="data">
                        <RadzenButton Icon="edit" ButtonStyle="Radzen.ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" Click="@(args => EditRow(data))" @onclick:stopPropagation="true">
                        </RadzenButton>
                        <RadzenButton ButtonStyle="Radzen.ButtonStyle.Danger" Icon="delete" Variant="Variant.Flat" Shade="Shade.Lighter" Size="ButtonSize.Medium" class="my-1 ms-1" Click="@(args => DeleteRow(data))" @onclick:stopPropagation="true">
                        </RadzenButton>
                    </Template>
                    <EditTemplate Context="data">
                        <RadzenButton Icon="check" ButtonStyle="Radzen.ButtonStyle.Success" Variant="Variant.Flat" Size="ButtonSize.Medium" Click="@((args) => SaveRow(data))" aria-label="Save">
                        </RadzenButton>
                        <RadzenButton Icon="close" ButtonStyle="Radzen.ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" class="my-1 ms-1" Click="@((args) => CancelEdit(data))" aria-label="Cancel">
                        </RadzenButton>
                        <RadzenButton ButtonStyle="Radzen.ButtonStyle.Danger" Icon="delete" Variant="Variant.Flat" Shade="Shade.Lighter" Size="ButtonSize.Medium" class="my-1 ms-1" Click="@(args => DeleteRow(data))" aria-label="Delete">
                        </RadzenButton>
                    </EditTemplate>
                </RadzenDataGridColumn>
            </Columns>
        </RadzenDataGrid>

        <Button Text="Add" OnClick="AddRowClick" />
    </RadzenRow>

</RadzenCard>
@inject IJSRuntime js;

@code {
    public List<ToiModel> tois = new List<ToiModel>();
    public RadzenDataGrid<ToiModel> grid;

    AlignItems alignItems = AlignItems.Normal;
    JustifyContent justifyContent = JustifyContent.Normal;
    string gap = "1rem";

    private double ZeroShotOffsetX = 11.9;

    private double ZeroShotOffsetY = 12.7;

    private double ShotWidth = 24.7;

    private double ShotHeight = 32.5;

    private double RotationDegree = 0;

    private double? FilterMaxRadius = null;

    private double? FilterMinRadius = null;

    private bool IsShowShotInside = true;

    private int ShotX;

    private int ShotY;

    private void MoveToTargetShot()
    {
        // 假设目标位置为 (350, 300)
        UpdateShotPosition(ShotX, ShotY);
    }

    public class Shot
    {
        public int GridX { get; set; }
        public int GridY { get; set; }
        public double DisplayX { get; set; }
        public double DisplayY { get; set; }

        public string _fillColor;
        public string FillColor
        {
            get
            {
                return IsSelect ? "#33bff3" : "#FFFFFF";
            }
            set
            {
                _fillColor = value;
            }
        }

        public bool CanSelect { get; set; } = false;

        public bool IsSelect { get; set; } = false;

        public List<ToiModel> Tois { get; set; } = new List<ToiModel>();
    }

    public class ToiModel
    {
        public double X { get; set; }

        public double Y { get; set; }

        public string Name { get; set; }
    }

    private List<Shot> Shots { get; set; } = new List<Shot>();
    private double currentX;
    private double currentY;
    private int currentGridX;
    private int currentGridY;




    protected override async Task OnInitializedAsync()
    {
        await js.InvokeVoidAsync("import", "./waferMap.js");
    }



    private DotNetObjectReference<WaferMap> _dotNetRef;


    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            // 初始化 DotNetObjectReference
            _dotNetRef = DotNetObjectReference.Create(this);
        }
    }

    private async Task GenerateWaferMap()
    {
        InitializeShots();
        await js.InvokeVoidAsync("drawWafer", RotationDegree, Shots, ShotWidth, ShotHeight, _dotNetRef, FilterMaxRadius, FilterMinRadius);
    }

    private void InitializeShots()
    {
        double waferRadius = 150;

        Shots = new List<Shot>();

        double waferCenterX = 200;
        double waferCenterY = 200;

        // 计算 (0,0) 位置的中心点
        double zeroShotCenterX = waferCenterX + ZeroShotOffsetX;
        double zeroShotCenterY = waferCenterY - ZeroShotOffsetY;

        // 计算最大可遍历的X和Y坐标（在一个正方形区域内遍历）
        int maxX = (int)Math.Ceiling(waferRadius / ShotWidth);
        int maxY = (int)Math.Ceiling(waferRadius / ShotHeight);

        // 遍历 X 轴和 Y 轴，生成 Shots，并确保它们在圆形区域内
        for (int gridX = -maxX; gridX <= maxX; gridX++)
        {
            for (int gridY = -maxY; gridY <= maxY; gridY++)
            {
                // 计算未旋转时Shot的中心点
                double shotAxisX = gridX * ShotWidth + ZeroShotOffsetX;
                double shotAxisY = gridY * ShotHeight + ZeroShotOffsetY;

                // 旋转Shot的坐标位置
                var (shotTransformedX, shotTransformedY) = TransformPosition(shotAxisX, shotAxisY, RotationDegree, waferCenterX, waferCenterY);

                var isInsideEdge = IsPointInsideCircle(shotTransformedX, shotTransformedY, ShotWidth, ShotHeight, waferRadius, waferCenterX, waferCenterY);
                if (!isInsideEdge)
                    continue;
                if (IsShowShotInside)
                {
                    if (IsShotInsideWafer(shotTransformedX, shotTransformedY, ShotWidth, ShotHeight, FilterMaxRadius ?? waferRadius, waferCenterX, waferCenterY))
                    {
                        Shots.Add(new Shot
                        {
                            GridX = gridX,
                            GridY = gridY,
                            DisplayX = shotTransformedX,
                            DisplayY = shotTransformedY,
                            Tois = tois,
                        });
                    }
                }
                else
                {
                    //展示所有Shot包含边界
                    Shots.Add(new Shot
                    {
                        GridX = gridX,
                        GridY = gridY,
                        DisplayX = shotTransformedX,
                        DisplayY = shotTransformedY,
                        Tois = tois,
                    });
                }
            }
        }
    }


    //只生成包含在圆内的Shot
    private bool IsShotInsideWafer(double shotAxisX, double shotAxisY, double shotWidth, double shotHeight, double waferRadius, double waferCenterX, double waferCenterY)
    {
        // 计算Shot的四个角
        double halfWidth = shotWidth / 2;
        double halfHeight = shotHeight / 2;

        // Shot的四个角点
        //var corners = new List<(double x, double y)>
        //{
        //   (shotAxisX- halfWidth, shotAxisY - halfHeight),
        //   (shotAxisX + halfWidth, shotAxisY - halfHeight),
        //    (shotAxisX - halfWidth, shotAxisY + halfHeight),
        //    (shotAxisX + halfWidth, shotAxisY + halfHeight)
        //};
        var corners = new List<(double x, double y)>
{
           (shotAxisX, shotAxisY),
           (shotAxisX, shotAxisY - shotHeight),
            (shotAxisX + shotWidth, shotAxisY - shotHeight),
            (shotAxisX + shotWidth, shotAxisY )
        };

        // 检查每个角是否都在圆内
        foreach (var corner in corners)
        {
            // 计算角点到晶圆中心的距离，如果超过半径，则表示在圆外
            if (Math.Sqrt(Math.Pow(corner.x - waferCenterX, 2) + Math.Pow(corner.y - waferCenterY, 2)) > waferRadius)
            {
                return false;
            }
        }
        return true;
    }

    private (double x, double y) TransformPosition(double x, double y, double rotationDegrees, double waferCenterX, double waferCenterY)
    {
        // 将角度转换为弧度
        double radians = (double)(rotationDegrees * Math.PI / 180);

        // 应用旋转矩阵
        double rotatedX = (double)(Math.Cos(radians) * x - Math.Sin(radians) * y);
        double rotatedY = (double)(Math.Sin(radians) * x - Math.Cos(radians) * y);

        // 平移到晶圆的中心位置
        return (waferCenterX + rotatedX, waferCenterY + rotatedY);
    }

    private void ShowShotInfo(Shot shot)
    {
        currentGridX = shot.GridX;
        currentGridX = shot.GridY;
        currentX = (shot.GridX * ShotWidth) + ZeroShotOffsetX;
        currentY = (shot.GridY * ShotHeight) + ZeroShotOffsetY;

    }

    public async Task UpdateShotPosition(int targetGridX, int targetGridY)
    {
        foreach (var shot in Shots)
        {
            if (shot.GridX == targetGridX && shot.GridY == targetGridY && targetGridX == 0 && targetGridY == 0)
                shot.FillColor = "pink";
            else if (shot.GridX == targetGridX && shot.GridY == targetGridY && targetGridX == 1 && targetGridY == 1)
                shot.FillColor = "skyblue";
            else if (shot.GridX == targetGridX && shot.GridY == targetGridY && targetGridX == 2 && targetGridY == 2)
                shot.FillColor = "green";
            else
                shot.FillColor = "white";
        }


        // 调用 JavaScript 更新目标 Shot
        await js.InvokeVoidAsync("drawWafer", RotationDegree, Shots, ShotWidth, ShotHeight, _dotNetRef, FilterMaxRadius, FilterMinRadius);

        StateHasChanged();
    }

    [JSInvokable]
    public async Task OnShotClick(int gridX, int gridY)
    {
        var random = new Random();
        foreach (var shot in Shots)
        {
            if (shot.GridX == gridX && shot.GridY == gridY)
                shot.IsSelect = !shot.IsSelect;
        }

        // 调用 JavaScript 更新目标 Shot
        await js.InvokeVoidAsync("drawWafer", RotationDegree, Shots, ShotWidth, ShotHeight, _dotNetRef, FilterMaxRadius, FilterMinRadius);

        await InvokeAsync(StateHasChanged);
    }

    public void Dispose()
    {
        _dotNetRef?.Dispose();
    }


    List<ToiModel> ordersToUpdate = new List<ToiModel>();

    public void OnUpdateRow(ToiModel data)
    {
        Reset(data);
    }

    public void Reset(ToiModel data = null)
    {
        if (data != null)
        {
            ordersToUpdate.Remove(data);
        }
        else
        {
            ordersToUpdate.Clear();
        }
    }

    public async Task EditRow(ToiModel data)
    {
        Reset();

        ordersToUpdate.Add(data);
        await grid.EditRow(data);
    }

    public async Task DeleteRow(ToiModel data)
    {
        Reset(data);
        if (tois.Contains(data))
        {
            tois.Remove(data);
            await grid.Reload();
        }
        else
        {
            grid.CancelEditRow(data);
            await grid.Reload();
        }
    }

    async Task SaveRow(ToiModel order)
    {
        await grid.UpdateRow(order);
        var poiOtherData = tois.FindAll(s => !s.Equals(order)).ToList();
    }

    public string columnEditing;

    public bool IsEditing(string columnName, ToiModel data)
    {
        return columnEditing == columnName && ordersToUpdate.Contains(data);
    }

    void CancelEdit(ToiModel order)
    {
        Reset(order);

        grid.CancelEditRow(order);
    }

    public async Task AddRowClick()
    {
        tois.Add(new ToiModel
        {
            Name = "Toi",
            X = 0,
            Y = 0,
        });
        grid.Reload();
    }

    public async Task FilterRadiusClick()
    {
        if (!FilterMaxRadius.HasValue || !FilterMinRadius.HasValue)
            return;

        double waferCenterX = 200;
        double waferCenterY = 200;
        var selectShots = Shots.Where(s => s.IsSelect);
        foreach (var item in selectShots)
        {
            var isInsideEdge = IsPointInsideCircle(item.DisplayX, item.DisplayY, ShotWidth, ShotHeight, FilterMaxRadius.Value, waferCenterX, waferCenterY);
            var isInside = IsShotInsideWafer(item.DisplayX, item.DisplayY, ShotWidth, ShotHeight, FilterMinRadius.Value, waferCenterX, waferCenterY);
            item.IsSelect = isInsideEdge && !isInside;
        }
        var ss = Shots.Where(s => s.IsSelect).ToList();
        await js.InvokeVoidAsync("drawWafer", RotationDegree, Shots, ShotWidth, ShotHeight, _dotNetRef, FilterMaxRadius, FilterMinRadius);
    }

    /// <summary>
    /// 检查点是否在圆形内部或边缘
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="CenterX"></param>
    /// <param name="CenterY"></param>
    /// <param name="Radius">半径</param>
    /// <returns></returns>
    public static bool IsPointInsideCircle(double shotAxisX, double shotAxisY, double shotWidth, double shotHeight, double waferRadius, double waferCenterX, double waferCenterY)
    {
        // 计算Shot的四个角
        double halfWidth = shotWidth / 2;
        double halfHeight = shotHeight / 2;

        // Shot的四个角点
        //var corners = new List<(double x, double y)>
        //{
        //   (shotAxisX- halfWidth, shotAxisY - halfHeight),
        //   (shotAxisX + halfWidth, shotAxisY - halfHeight),
        //    (shotAxisX - halfWidth, shotAxisY + halfHeight),
        //    (shotAxisX + halfWidth, shotAxisY + halfHeight)
        //};
        var corners = new List<(double x, double y)>
    {
           (shotAxisX, shotAxisY),
           (shotAxisX, shotAxisY - shotHeight),
            (shotAxisX + shotWidth, shotAxisY - shotHeight),
            (shotAxisX + shotWidth, shotAxisY )
        };

        // 检查每个角是否都在圆内
        foreach (var corner in corners)
        {
            double distanceFromCenter = Math.Sqrt(Math.Pow(corner.x - waferCenterX, 2) + Math.Pow(corner.y - waferCenterY, 2));
            if (distanceFromCenter <= waferRadius)
            {
                return true;
            }
        }
        return false;

    }
}


